package com.stockz.ui.swing.charting.display.indicator;

import java.awt.Graphics2D;
import java.util.List;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.stockz.core.model.Bar;
import com.stockz.core.util.BarUtil;
import com.stockz.core.util.ListUtil;
import com.stockz.core.util.BarUtil.BarValueType;
import com.stockz.ui.swing.charting.painter.indicator.BarIndicatorPainter;
import com.stockz.ui.swing.charting.util.UIChartingConstant.OVERLAY;


@Component
@Scope("prototype")
public class BullishClimaticVolume extends AbstractDisplayableIndicatorConfiguration {
	public static class Configuration{
		private double averageTradeSizeMultiple = 2;
		private double volumeMultiple = 3;
		private double stochasticsUpperLimit = 30;
		private int shortSpan = 5;
		private int longSpan = 20;
		private boolean volumeOnly = false;
		public double getAverageTradeSizeMultiple() {
			return averageTradeSizeMultiple;
		}
		public void setAverageTradeSizeMultiple(double averageTradeSizeMultiple) {
			this.averageTradeSizeMultiple = averageTradeSizeMultiple;
		}
		public double getVolumeMultiple() {
			return volumeMultiple;
		}
		public void setVolumeMultiple(double volumeMultiple) {
			this.volumeMultiple = volumeMultiple;
		}
		public double getStochasticsUpperLimit() {
			return stochasticsUpperLimit;
		}
		public void setStochasticsUpperLimit(double stochasticsUpperLimit) {
			this.stochasticsUpperLimit = stochasticsUpperLimit;
		}
		public int getShortSpan() {
			return shortSpan;
		}
		public void setShortSpan(int shortSpan) {
			this.shortSpan = shortSpan;
		}
		public int getLongSpan() {
			return longSpan;
		}
		public void setLongSpan(int longSpan) {
			this.longSpan = longSpan;
		}
		public boolean isVolumeOnly() {
			return volumeOnly;
		}
		public void setVolumeOnly(boolean volumeOnly) {
			this.volumeOnly = volumeOnly;
		}
	}
	
	public static double value(List<Bar> barList, Configuration configuration){
		if(barList != null && barList.size() > configuration.longSpan){
			double volume = barList.get(0).getVolume();
			double volumeSimpleMovingAverage = SimpleMovingAverage.valueAll(ListUtil.convert(barList, BarValueType.VOLUME, 0, configuration.getLongSpan()));
			double stochastics = Stochastics.value(ListUtil.convert(barList, BarValueType.AVGPRICE, 0, configuration.getShortSpan()), configuration.getShortSpan());
			if(stochastics < 1){
				stochastics = 1;
			}
			if(!configuration.isVolumeOnly()){
				double averageTradeSizeSimpleMovingAverage = SimpleMovingAverage.valueAll(ListUtil.convert(barList, BarValueType.AVGTRADESIZE, 0, configuration.getLongSpan()));
				double averageTradeSize = BarUtil.getValue(barList.get(0),BarValueType.AVGTRADESIZE);
				return (volume*averageTradeSize)/(averageTradeSizeSimpleMovingAverage*
						volumeSimpleMovingAverage*stochastics);
			}else{
				return (volume/volumeSimpleMovingAverage*stochastics);
			}
		}
		return 0;
	}
	
	public static double[] values(List<Bar> barList, Configuration configuration){
		if(barList != null && barList.size() > configuration.longSpan){
			double[] volumeSimpleMovingAverage = SimpleMovingAverage.values(ListUtil.convert(barList, BarValueType.VOLUME),configuration.getLongSpan());
			double[] stochastics = Stochastics.values(ListUtil.convert(barList, BarValueType.AVGPRICE), configuration.getShortSpan());
			double[] values = new double[barList.size()];
			
			double[] averageTradeSizeSimpleMovingAverage = null; 
			
			if(!configuration.isVolumeOnly()){
				averageTradeSizeSimpleMovingAverage = SimpleMovingAverage.values(ListUtil.convert(barList, BarValueType.AVGTRADESIZE),configuration.getLongSpan());
			}
					
			
			for(int i = barList.size() - configuration.getLongSpan() - 1; i >=0; i--){
				double averageTradeSize = BarUtil.getValue(barList.get(i),BarValueType.AVGTRADESIZE);
				double volume = barList.get(i).getVolume();
				if(stochastics[i] < 1){
					stochastics[i] = 1;
				}
				if(configuration.isVolumeOnly()){
					values[i] = volume/volumeSimpleMovingAverage[i]*stochastics[i];
				}else{
					values[i] = (volume*averageTradeSize)
							/(averageTradeSizeSimpleMovingAverage[i]*
							volumeSimpleMovingAverage[i]*
							stochastics[i]);
				}
				
			}
			return values;
		}
		
		return new double[0];
	}
	
	private Configuration configuration = new Configuration();
	
	@Override
	public void paint(Graphics2D g) {
		BarIndicatorPainter.paint(g, this);
	}
	
	@Override
	public String getFullName() {
		return "Bullish Climatic Volume";
	}

	@Override
	public String getShortName() {
		return "BCV";
	}

	@Override
	public String getDescription() {
		return getShortName()+","+configuration.getLongSpan();
	}
	
	@Override
	public OVERLAY getOverlay() {
		return OVERLAY.INDEPENDENT;
	}

	@Override
	public boolean isOverlappable() {
		return false;
	}

	@Override
	public Object getConfiguration() {
		return configuration;
	}

	@Override
	public void refreshValues() {
		List<Bar> barList = getStockChartPanel().getStockChartPanelState().getBarList();
		setValues(values(barList,configuration));
	}

}
